package com.zhulong.saas.cloud.gateway.adapt;

import com.zhulong.common.basic.dto.Response;
import com.zhulong.common.basic.exception.BasicErrorCode;
import com.zhulong.common.basic.exception.BusinessException;
import com.zhulong.saas.cloud.gateway.security.SubjectBusTypeEnum;
import com.zhulong.saas.subject.internal.business.api.SubjectPlatformRelInternalServiceI;
import com.zhulong.saas.subject.internal.business.dto.SubjectPlatformRelIntDTO;
import com.zhulong.saas.subject.internal.business.dto.SubjectPlatformRelQueryDto;
import com.zhulong.saas.tenant.internal.domain.api.PlatformDomainInternalServiceI;
import com.zhulong.saas.tenant.internal.domain.dto.PlatformDomainIntDTO;
import com.zhulong.saas.tenant.internal.domain.dto.PlatformDomainQueryDto;
import com.zhulong.saas.tenant.internal.platform.api.PlatformInternalServiceI;
import com.zhulong.saas.tenant.internal.platform.dto.PlatformIntDTO;
import com.zhulong.saas.tenant.internal.platform.dto.PlatformQueryDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.cache.RedisCacheManager;

import java.util.Collections;
import java.util.List;

/**
 * 此处需要加入缓存处理，每次请求都进行判断十分消耗性能
 */
@Slf4j
public class UserAdaptImpl implements UserAdapt, ApplicationContextAware {

    public static final String SUBJECT_BUSTYPE_CACHE_NAME = "subject_bustype";

    public static final String SUBJECT_TENANT_CACHE_NAME = "subject_tenant";

    public static String HOST_TENANT_CACHE_NAME = "host_tenant";

//    @Autowired
//    private  PlatformInternalServiceI platformInternalServiceI;
//
//    @Autowired
//    private SubjectPlatformRelInternalServiceI subjectPlatformRelInternalServiceI;

    @Autowired
    private RedisCacheManager cacheManager;

    private ApplicationContext applicationContext;

    @Override
    public Boolean checkSubjectBusType(Long subjectId, Long tenantId, List<SubjectBusTypeEnum> subjectBusTypes) {
        //从缓存中获取，
        log.debug("进入用户适配器，checkSubjectBusType方法");
        List<SubjectPlatformRelIntDTO> relIntDTOS = cacheManager.getCache(SUBJECT_BUSTYPE_CACHE_NAME).get(subjectId, List.class);
        if (relIntDTOS == null) {
            log.debug("checkSubjectBusType缓存未匹配，进入查询");
            SubjectPlatformRelQueryDto queryDto = new SubjectPlatformRelQueryDto();
            queryDto.setSubjectId(subjectId);
            Response<List<SubjectPlatformRelIntDTO>> platformRelDTOResp = this.applicationContext.getBean(SubjectPlatformRelInternalServiceI.class).findSubjectPlatformRelByCondition(queryDto);
            if (!platformRelDTOResp.isSuccess()) {
                throw new BusinessException(BasicErrorCode.INVOKE_ERROR, "调用接口失败，错误code:" + platformRelDTOResp.getErrMessage() + ",错误原因：" + platformRelDTOResp.getErrMessage());
            }
            if (platformRelDTOResp.getData() == null) {
                relIntDTOS = Collections.EMPTY_LIST;
            } else {
                relIntDTOS = platformRelDTOResp.getData();
            }
            cacheManager.getCache(SUBJECT_BUSTYPE_CACHE_NAME).put(subjectId, relIntDTOS);
        }

        return relIntDTOS.stream().filter(dto -> dto.getPlatformId().equals(tenantId)).anyMatch(dto -> {
            Boolean exist = subjectBusTypes.stream().anyMatch(busType -> busType.getCode().equals(dto.getBusinessType()));
            return exist;
        });
    }

    @Override
    public Boolean checkSubjectIsTheTenant(Long subject, Long tenant) {
        List<PlatformIntDTO> platformIntDTOS = cacheManager.getCache(SUBJECT_TENANT_CACHE_NAME).get(subject, List.class);
        if (platformIntDTOS == null) {
            log.debug("获取主体申请的租户，未命中到缓存");
            PlatformQueryDto platformQueryDto = new PlatformQueryDto();
            platformQueryDto.setSubjectId(subject);
            Response<List<PlatformIntDTO>> response = this.applicationContext.getBean(PlatformInternalServiceI.class).findPlatformByCondition(platformQueryDto);
            if (!response.isSuccess()) {
                throw new BusinessException(BasicErrorCode.INVOKE_ERROR, "调用接口失败，错误code:" + response.getErrMessage() + ",错误原因：" + response.getErrMessage());
            }
            if (response.getData() == null) {
                platformIntDTOS = Collections.EMPTY_LIST;
            } else {
                platformIntDTOS = response.getData();
            }
            cacheManager.getCache(SUBJECT_TENANT_CACHE_NAME).put(subject, platformIntDTOS);
        }
        return platformIntDTOS.stream().anyMatch(platformIntDTO -> platformIntDTO.getPlatformId().equals(tenant));
    }

    @Override
    public Long getTenantByHost(String host, Long defaultTenantId) {

        Long tenantId = cacheManager.getCache(HOST_TENANT_CACHE_NAME).get(host, Long.class);
        if (tenantId == null) {
            log.debug("判断租户id,{}未命中缓存，进行接口查询");
            String domain = extractDomainValue(host);
            PlatformDomainInternalServiceI domainInternalServiceI = this.applicationContext.getBean(PlatformDomainInternalServiceI.class);
            PlatformDomainQueryDto queryDto = new PlatformDomainQueryDto();
            queryDto.setDomainName(domain);
            Response<List<PlatformDomainIntDTO>> response = domainInternalServiceI.findDomainByCondition(queryDto);
            if (!response.isSuccess()) {
                throw new BusinessException(BasicErrorCode.INVOKE_ERROR, "调用接口失败，错误code:" + response.getErrMessage() + ",错误原因：" + response.getErrMessage());
            }
            List<PlatformDomainIntDTO> domainList = response.getData();
            if (domainList == null || domainList.isEmpty()) {
                tenantId = defaultTenantId;
            } else {
                tenantId = response.getData().get(0).getPlatformId();
            }
            cacheManager.getCache(HOST_TENANT_CACHE_NAME).put(host, tenantId);
        }
        return tenantId;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private String extractDomainValue(String host) {
        return host;
    }

}
